use glass::{Members, Reflect};
use std::marker::PhantomData;

use crate::Validator;

pub struct EnumerValidator<Enumer: Reflect> {
    marker: PhantomData<Enumer>,
}

impl<Enumer: Reflect> Default for EnumerValidator<Enumer> {
    fn default() -> Self {
        Self {
            marker: PhantomData,
        }
    }
}

impl<Enumer: Reflect> Validator<String> for EnumerValidator<Enumer> {
    type Error = String;

    fn validate(
        &self,
        ident: Option<&str>,
        name: Option<&str>,
        data: &String,
    ) -> Result<(), Self::Error> {
        let members = Enumer::members();
        if let Members::Variants(variants) = members {
            for variant in variants {
                if variant.ident.eq(data) {
                    return Ok(());
                }
            }
        }
        let field = name.or(ident).unwrap_or_default();
        Err(format!("无效的{field}枚举值: {data}"))
    }
}

impl<Enumer: Reflect> Validator<isize> for EnumerValidator<Enumer> {
    type Error = String;

    fn validate(
        &self,
        ident: Option<&str>,
        name: Option<&str>,
        data: &isize,
    ) -> Result<(), Self::Error> {
        let members = Enumer::members();
        if let Members::Variants(variants) = members {
            for variant in variants {
                let value = variant.value.unwrap_or(variant.index as isize);
                if value.eq(data) {
                    return Ok(());
                }
            }
        }
        let field = name.or(ident).unwrap_or_default();
        Err(format!("无效的{field}枚举值: {data}"))
    }
}

impl<Enumer: Reflect> Validator<i32> for EnumerValidator<Enumer> {
    type Error = String;

    fn validate(
        &self,
        ident: Option<&str>,
        name: Option<&str>,
        data: &i32,
    ) -> Result<(), Self::Error> {
        let data = *data as isize;
        <EnumerValidator<Enumer> as Validator<isize>>::validate(self, ident, name, &data)
    }
}

impl<Enumer: Reflect> Validator<u32> for EnumerValidator<Enumer> {
    type Error = String;

    fn validate(
        &self,
        ident: Option<&str>,
        name: Option<&str>,
        data: &u32,
    ) -> Result<(), Self::Error> {
        let data = *data as isize;
        <EnumerValidator<Enumer> as Validator<isize>>::validate(self, ident, name, &data)
    }
}

impl<Enumer: Reflect> Validator<i8> for EnumerValidator<Enumer> {
    type Error = String;

    fn validate(
        &self,
        ident: Option<&str>,
        name: Option<&str>,
        data: &i8,
    ) -> Result<(), Self::Error> {
        let data = *data as isize;
        <EnumerValidator<Enumer> as Validator<isize>>::validate(self, ident, name, &data)
    }
}

impl<Enumer: Reflect> Validator<u8> for EnumerValidator<Enumer> {
    type Error = String;

    fn validate(
        &self,
        ident: Option<&str>,
        name: Option<&str>,
        data: &u8,
    ) -> Result<(), Self::Error> {
        let data = *data as isize;
        <EnumerValidator<Enumer> as Validator<isize>>::validate(self, ident, name, &data)
    }
}

#[cfg(test)]
mod tests {
    use crate::{Validator, impls::enumer::EnumerValidator};
    use glass::Reflect;

    #[test]
    fn test_enumer_validator() {
        #[derive(Reflect)]
        enum Sex {
            Man,
            Woman,
        }
        let _uname_0 = 1;

        let sex = Sex::Man as i32;
        assert!(
            EnumerValidator::<Sex>::default()
                .validate(None, None, &sex)
                .is_ok()
        );
    }
}
